<template>
  <view class="leave-form-base">
    <view class="section-card">
      <u-tabs
        :list="tabList"
        :current="currentTab"
        @change="handleTabChange"
        :scrollable="false"
        lineColor="#5f87ff"
        :activeStyle="{ color: '#1f2b5b', fontWeight: 600 }"
        :inactiveStyle="{ color: '#8b90a5' }"
      ></u-tabs>

      <!-- 申请信息 Tab -->
      <view v-show="currentTab === 0" class="tab-content">
        <!-- 基础信息 -->
        <view class="section-title">基础信息</view>
        <view class="form-grid">
          <view class="form-item inline">
            <text class="label">填报{{ formType === 'internal' ? '部门' : '单位' }}:</text>
            <view class="field">
              <u-input
                v-model="formData.departmentName"
                :disabled="isViewMode"
                placeholder=""
                :custom-style="inputCustomStyle"
              />
            </view>
          </view>
          <view class="form-item inline">
            <text class="label">填报时间:</text>
            <view class="field picker-wrapper">
              <uni-datetime-picker
                v-model="reportDate"
                type="date"
                :disabled="isViewMode"
                @change="handleReportDateChange"
              />
            </view>
          </view>
          <view class="form-item inline">
            <text class="label">姓名:</text>
            <view class="field">
              <u-input
                v-model="formData.applicantName"
                :disabled="isViewMode"
                placeholder=""
                :custom-style="inputCustomStyle"
              />
            </view>
          </view>
          <view class="form-item inline">
            <text class="label">职务:</text>
            <view class="field">
              <u-input
                v-model="formData.applicantPosition"
                :disabled="isViewMode"
                placeholder=""
                :custom-style="inputCustomStyle"
              />
            </view>
          </view>
        </view>
        <view class="form-item inline">
          <text class="label">事由:</text>
          <u-textarea
            v-model="formData.reason"
            :disabled="isViewMode"
            placeholder=""
            autoHeight
            maxlength="200"
            :custom-style="textareaCustomStyle"
          />
        </view>
        <view class="form-grid">
          <view class="form-item inline">
            <text class="label">地点:</text>
            <u-input
              v-model="formData.location"
              :disabled="isViewMode"
              placeholder=""
              :custom-style="inputCustomStyle"
            />
          </view>
        </view>
        <view class="form-grid">
          <view class="form-item inline">
            <text class="label">开始时间:</text>
            <view class="field picker-wrapper">
              <uni-datetime-picker
                v-model="formData.startTime"
                type="datetime"
                :disabled="isViewMode"
                hide-second="true"
                @change="handleStartTimeChange"
              />
            </view>
          </view>
          <view class="form-item inline">
            <text class="label">结束时间:</text>
            <view class="field picker-wrapper">
              <uni-datetime-picker
                v-model="formData.endTime"
                type="datetime"
                :disabled="isViewMode"
                hide-second="true"
                @change="handleEndTimeChange"
              />
            </view>
          </view>
          <!-- <view class="form-item inline">
            <text class="label">时长(天):</text>
            <view class="field">
              <u-input v-model="totalDaysText" disabled :custom-style="inputCustomStyle" />
            </view>
          </view> -->
        </view>
        <view class="form-grid">
          <view class="form-item">
            <text class="label">临时负责人:</text>
            <u-input
              v-model="formData.temporaryContactPerson"
              :disabled="isViewMode"
              placeholder=""
              :custom-style="inputCustomStyle"
            />
          </view>
          <view class="form-item">
            <text class="label">负责人职务:</text>
            <u-input
              v-model="formData.temporaryContactPosition"
              :disabled="isViewMode"
              placeholder=""
              :custom-style="inputCustomStyle"
            />
          </view>
          <view class="form-item">
            <text class="label">负责人电话:</text>
            <u-input
              v-model="formData.temporaryContactPhone"
              :disabled="isViewMode"
              placeholder=""
              type="number"
              :custom-style="inputCustomStyle"
            />
          </view>
        </view>

        <!-- 附件 -->
        <view class="section-title">附件:</view>
        <view class="attachment-section">
          <view v-if="attachmentList.length" class="attachment-list">
            <view
              class="attachment-item"
              v-for="item in attachmentList"
              :key="item.id || item.fileName"
            >
              <view class="info" @click="handleAttachmentPreview(item)">
                <u-icon name="file-text" color="#2979ff" size="22" />
                <text class="name">{{ item.fileName }}</text>
              </view>
              <u-icon
                v-if="!isViewMode"
                name="trash"
                color="#f56c6c"
                size="20"
                @click="handleAttachmentRemove(item)"
              />
            </view>
          </view>
          <view v-else class="empty-attachment">暂无附件</view>

          <view v-if="!isViewMode" class="upload-box">
            <yt-upload
              ref="ytUploadRef"
              childId="leaveApplicationUpload"
              width="100%"
              height="120rpx"
              :option="uploadOption"
              :count="5"
              :size="100"
              :instantly="false"
              :debug="true"
              formats=""
              @change="onFileChange"
              @progress="onUploadProgress"
              @uploadEnd="onUploadEnd"
            >
              <view class="upload-btn-slot">
                <text class="upload-icon">📁</text>
                <text class="upload-text">选择文件</text>
              </view>
            </yt-upload>
            <text class="upload-tip">支持多文件上传，最多5个，每个最大100MB</text>

            <!-- 文件列表 -->
            <view class="file-list" v-if="fileList.length > 0">
              <view class="file-item" v-for="file in fileList" :key="file.name">
                <view class="file-info">
                  <text class="file-name">{{ file.name }}</text>
                  <text class="file-size">{{ formatFileSize(file.size) }}</text>
                  <text class="file-status" :class="'status-' + file.type">
                    {{ getStatusText(file.type) }}
                  </text>
                </view>
                <text class="file-delete" @click="removeFile(file.name)">×</text>
              </view>
            </view>
          </view>
        </view>

        <!-- 备注 -->
        <view class="section-title remark-inline">备注</view>
        <u-textarea
          v-model="remarkText"
          :disabled="isViewMode"
          autoHeight
          count
          placeholder=""
          :custom-style="textareaCustomStyle"
        />

        <!-- 报送信息 -->
        <view class="section-title remark-inline" v-if="formType !== 'internal'">报送信息</view>
        <view class="form-grid" v-if="formType !== 'internal'">
          <view class="form-item inline">
            <text class="label">报送单位联系人:</text>
            <view class="field">
              <u-input
                v-model="formData.reportingContactPerson"
                :disabled="isViewMode"
                placeholder=""
                :custom-style="inputCustomStyle"
              />
            </view>
          </view>
          <view class="form-item inline">
            <text class="label">联系电话:</text>
            <view class="field">
              <u-input
                v-model="formData.reportingContactPhone"
                :disabled="isViewMode"
                placeholder=""
                type="number"
                :custom-style="inputCustomStyle"
              />
            </view>
          </view>
        </view>
      </view>

      <!-- 流程记录 Tab -->
      <view v-show="currentTab === 1" class="tab-content">
        <view v-if="flowRecords.length" class="flow-timeline">
          <view
            class="flow-item"
            v-for="(record, index) in flowRecords"
            :key="record.id || `${record.stepName}-${record.approverName}`"
          >
            <view class="flow-content">
              <!-- 左侧时间线 -->
              <view class="flow-timeline-left">
                <!-- 状态圆点 -->
                <view class="flow-status-dot" :class="getRecordStatusClass(record)"></view>
                <!-- 连接线（最后一个不显示） -->
                <view
                  v-if="index < flowRecords.length - 1"
                  class="flow-line"
                  :class="getLineClass(record, flowRecords[index + 1])"
                ></view>
              </view>
              <!-- 右侧内容 -->
              <view class="flow-right">
                <view class="flow-header">
                  <text class="step-name">{{ record.stepName || '流程节点' }}</text>
                  <u-tag
                    :text="getRecordStatusText(record)"
                    size="mini"
                    :type="getRecordStatusType(record)"
                    plain
                  />
                </view>
                <view class="flow-body">
                  <text class="approver-label">审批人:</text>
                  <text class="approver-name">{{ record.approverName || '-' }}</text>
                </view>
                <view class="flow-opinion-box" v-if="record.opinion">
                  <text class="opinion-label">审批意见:</text>
                  <text class="opinion-text">{{ record.opinion }}</text>
                </view>
                <view class="flow-time">
                  <text v-if="isRecordCompleted(record)">
                    {{ formatRecordDate(record) }}
                  </text>
                  <text v-else class="waiting-text">待审批</text>
                </view>
              </view>
            </view>
          </view>
        </view>
        <u-empty v-else mode="history" text="暂无流程记录" />
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'
import {
  createLeaveApplication,
  deleteLeaveAttachment,
  getLeaveApplicationDetail,
  type LeaveApplicationAttachment,
  type LeaveApplicationDetail,
  type LeaveApplicationFormData,
  type LeaveApplicationApprovalRecord,
  updateLeaveApplication,
} from '@/Api/leave'
import { UserManager } from '@/utils/user'
import { useMemberStore } from '@/stores/modules/member'
import envConfig from '@/config/env'

const props = withDefaults(
  defineProps<{
    templateId?: number | null
    templateName?: string
    mode?: 'create' | 'edit' | 'view'
    leaveId?: number | null
    formType?: 'internal' | 'leave'
  }>(),
  {
    templateId: null,
    templateName: '请假申请',
    mode: 'create',
    leaveId: null,
    formType: 'leave',
  },
)

const emit = defineEmits<{
  (e: 'save-success', id?: number): void
  (e: 'submit-success', id?: number): void
  (e: 'attachment-removed', attachmentId: number): void
}>()

const isViewMode = computed(() => props.mode === 'view')
const locationLabel = computed(() => (props.formType === 'internal' ? '地点' : '地点'))

const currentTab = ref(0)
const tabList = [{ name: '申请信息' }, { name: '流程记录' }]

const handleTabChange = (item: any, index: number) => {
  currentTab.value = index
}

const userInfo = (UserManager.getFullUserInfo() as any) || {}

const inputCustomStyle = {
  background: 'transparent',
  border: 'none',
  borderBottom: '2rpx solid #dce2ff',
  borderRadius: 0,
  padding: '0 8rpx',
  height: '68rpx',
  fontSize: '30rpx',
  boxShadow: 'none',
}

const textareaCustomStyle = {
  background: 'transparent',
  border: 'none',
  borderBottom: '2rpx solid #dce2ff',
  borderRadius: 0,
  padding: '10rpx 8rpx 24rpx',
  fontSize: '30rpx',
  boxShadow: 'none',
}

const createDefaultFormData = (): LeaveApplicationFormData => ({
  id: undefined,
  companyId: Number(userInfo.companyId || 1),
  companyName: userInfo.companyName || '阳泉市卫健委',
  departmentId: Number(userInfo.mainDeptId || userInfo.deptId || 0),
  departmentName: userInfo.deptName || userInfo.department || '',
  applicantId: Number(userInfo.id || 0),
  applicantName: userInfo.nickname || userInfo.name || '',
  applicantPosition: (userInfo as any)?.position || '',
  leaveTypeId: props.formType === 'leave' ? 1 : 2,
  leaveTypeName: props.formType === 'leave' ? '请假申请' : '外出报备',
  flowTemplateId: props.templateId ? Number(props.templateId) : 0,
  flowTemplateName: props.templateName || (props.formType === 'leave' ? '请假申请' : '外出报备'),
  startTime: '',
  endTime: '',
  totalDays: 0,
  reason: '',
  location: '',
  temporaryContactPerson: '',
  temporaryContactPosition: '',
  temporaryContactPhone: '',
  reportingContactPerson: '',
  reportingContactPhone: '',
  isInternal: props.formType === 'internal' ? 0 : 1,
  remark: '',
})

const formData = reactive<LeaveApplicationFormData>(createDefaultFormData())
const formatDate = (date: Date) => date.toISOString().split('T')[0]
const reportDate = ref(formatDate(new Date()))
const remarkText = ref('')
const flowRecords = ref<LeaveApplicationApprovalRecord[]>([])
const attachmentList = ref<LeaveApplicationAttachment[]>([])
const fileList = ref<any[]>([])
const filesMap = ref(new Map())

// yt-upload 组件引用
const ytUploadRef = ref<any>(null)

// 上传状态（H5 和 APP 共用）
const uploadStatus = ref({
  isUploading: false,
  uploadedCount: 0,
  totalCount: 0,
  firstResponse: null as any,
  leaveId: null as any,
  resolve: null as any,
  reject: null as any,
})

const submitting = ref(false)

const totalDaysText = computed(() => (formData.totalDays ? `${formData.totalDays}` : '-'))

// yt-upload 上传配置（H5 和 APP 都使用 UniApp 专用接口）
// 使用 ref 而不是 computed，避免每次访问时重新计算导致 setData 的设置被覆盖
const uploadOption = ref({
  url: '',
  name: 'file',
  header: {},
  formData: {
    request: '',
  },
})

// 更新 uploadOption（当有 leaveId 时）
const updateUploadOption = (leaveId: number) => {
  const memberStore = useMemberStore()
  const userInfo = memberStore.profile
  const token = uni.getStorageSync('token')

  uploadOption.value = {
    url: `${envConfig.baseUrl}/leave/application/${leaveId}/attachments`,
    name: 'file', // 附件上传接口接收单个文件
    header: {
      satoken: token || '',
      Authorization: token ? `Bearer ${token}` : '',
      'X-User-Id': userInfo?.id ? String(userInfo.id) : '',
      'X-Username': userInfo?.username ? encodeURIComponent(userInfo.username) : '',
      'X-Real-Name': userInfo?.nickname
        ? encodeURIComponent(userInfo.nickname || userInfo.realName || userInfo.name || '')
        : '',
      'X-Company-Id': userInfo?.companyId ? String(userInfo.companyId) : '',
      'X-Company-Name': userInfo?.companyName ? encodeURIComponent(userInfo.companyName || '') : '',
    },
    formData: {} as any, // 附件上传接口不需要额外的 formData，只需要文件
  }
}

// 初始化 uploadOption（默认值，保存后会被更新）
const initUploadOption = () => {
  uploadOption.value = {
    url: '',
    name: 'file',
    header: {},
    formData: {} as any,
  }
}

// 初始化
initUploadOption()

const resetForm = () => {
  Object.assign(formData, createDefaultFormData())
  remarkText.value = ''
  reportDate.value = formatDate(new Date())
  flowRecords.value = []
  attachmentList.value = []
  fileList.value = []
  filesMap.value = new Map()
}

const applyDetailData = (detail: LeaveApplicationDetail) => {
  if (!detail) {
    console.warn('[applyDetailData] detail 为空')
    return
  }

  console.log('[applyDetailData] 开始填充数据:', detail)

  formData.id = detail.id
  formData.companyId = detail.companyId || formData.companyId
  formData.companyName = detail.companyName || formData.companyName
  formData.departmentId = detail.departmentId || formData.departmentId
  formData.departmentName = detail.departmentName || formData.departmentName
  formData.applicantId = detail.applicantId || formData.applicantId
  formData.applicantName = detail.applicantName || formData.applicantName
  formData.applicantPosition = detail.applicantPosition || formData.applicantPosition
  formData.leaveTypeName = detail.leaveTypeName || formData.leaveTypeName
  formData.flowTemplateId = detail.flowTemplateId || formData.flowTemplateId
  formData.flowTemplateName = detail.flowTemplateName || formData.flowTemplateName
  formData.startTime = detail.startTime || ''
  formData.endTime = detail.endTime || ''
  formData.totalDays = detail.totalDays || 0
  formData.reason = detail.reason || ''
  formData.location = detail.location || ''
  formData.temporaryContactPerson = detail.temporaryContactPerson || ''
  formData.temporaryContactPosition = detail.temporaryContactPosition || ''
  formData.temporaryContactPhone = detail.temporaryContactPhone || ''
  formData.reportingContactPerson = detail.reportingContactPerson || ''
  formData.reportingContactPhone = detail.reportingContactPhone || ''
  formData.remark = detail.remark || ''
  remarkText.value = detail.remark || ''
  reportDate.value = detail.startTime ? detail.startTime.substring(0, 10) : formatDate(new Date())

  console.log('[applyDetailData] 填充后的 formData:', formData)
}

const loadLeaveDetail = async (leaveId: number) => {
  if (!leaveId) {
    console.warn('[loadLeaveDetail] leaveId 为空')
    return
  }

  console.log('[loadLeaveDetail] 开始加载详情, leaveId:', leaveId)

  try {
    submitting.value = true
    const res: any = await getLeaveApplicationDetail(leaveId)

    console.log('[loadLeaveDetail] API 响应:', res)

    const body = res?.data || res
    if (body?.code && body.code !== 200) {
      throw new Error(body.message || '请假单详情获取失败')
    }
    const detail = (body?.data || body) as LeaveApplicationDetail

    console.log('[loadLeaveDetail] 解析后的 detail:', detail)

    applyDetailData(detail)
    attachmentList.value = (detail as any)?.attachments || []
    flowRecords.value = (detail as any)?.approvalRecords || []

    console.log('[loadLeaveDetail] 附件列表:', attachmentList.value)
    console.log('[loadLeaveDetail] 流程记录:', flowRecords.value)
  } catch (error) {
    console.error('[loadLeaveDetail] 加载请假单详情失败:', error)
    uni.showToast({ title: '加载详情失败', icon: 'none' })
  } finally {
    submitting.value = false
  }
}

watch(
  () => props.leaveId,
  (val) => {
    if (val) {
      loadLeaveDetail(Number(val))
    } else {
      resetForm()
    }
  },
  { immediate: true },
)

watch(
  () => props.templateId,
  (val) => {
    if (typeof val === 'number') {
      formData.flowTemplateId = val
    }
  },
)

watch(
  () => remarkText.value,
  (val) => {
    formData.remark = val
  },
)

const calculateTotalDays = () => {
  if (formData.startTime && formData.endTime) {
    const start = new Date(formData.startTime).getTime()
    const end = new Date(formData.endTime).getTime()
    if (end > start) {
      const diff = end - start
      const days = diff / (1000 * 60 * 60 * 24)
      // 保留4位小数，精确计算实际天数（不设最小值，保持实际计算结果）
      const roundedDays = Math.round(days * 10000) / 10000
      formData.totalDays = roundedDays
    } else {
      // 如果结束时间早于或等于开始时间，设置为0（由后端验证处理）
      formData.totalDays = 0
    }
  }
}

// 处理开始时间变化，保留用户选择的时间（精确到分钟）
const handleStartTimeChange = (val: string) => {
  if (!val) return

  // 如果只包含日期部分（格式为 YYYY-MM-DD），则添加默认时间 00:00
  if (val.match(/^\d{4}-\d{2}-\d{2}$/)) {
    formData.startTime = `${val} 00:00:00`
  } else if (val.includes(' ')) {
    // 如果包含时间部分，保留用户选择的时间，确保格式为 YYYY-MM-DD HH:mm:ss
    const parts = val.split(' ')
    const datePart = parts[0]
    const timePart = parts[1] || '00:00:00'
    // 如果时间部分只有 HH:mm，补充秒数
    if (timePart.match(/^\d{2}:\d{2}$/)) {
      formData.startTime = `${datePart} ${timePart}:00`
    } else {
      formData.startTime = val
    }
  } else {
    formData.startTime = val
  }

  calculateTotalDays()
}

// 处理结束时间变化，保留用户选择的时间（精确到分钟）
const handleEndTimeChange = (val: string) => {
  if (!val) return

  // 如果只包含日期部分（格式为 YYYY-MM-DD），则添加默认时间 23:59
  if (val.match(/^\d{4}-\d{2}-\d{2}$/)) {
    formData.endTime = `${val} 23:59:59`
  } else if (val.includes(' ')) {
    // 如果包含时间部分，保留用户选择的时间，确保格式为 YYYY-MM-DD HH:mm:ss
    const parts = val.split(' ')
    const datePart = parts[0]
    const timePart = parts[1] || '23:59:59'
    // 如果时间部分只有 HH:mm，补充秒数
    if (timePart.match(/^\d{2}:\d{2}$/)) {
      formData.endTime = `${datePart} ${timePart}:59`
    } else {
      formData.endTime = val
    }
  } else {
    formData.endTime = val
  }

  calculateTotalDays()
}

const handleReportDateChange = (val: string) => {
  if (val && formData.startTime) {
    formData.startTime = `${val} ${formData.startTime.substring(11) || '00:00:00'}`
  } else if (val) {
    formData.startTime = `${val} 00:00:00`
  }
}

// 文件选择回调
const onFileChange = (files: Map<string, any>) => {
  filesMap.value = files
  fileList.value = Array.from(files.values())
}

// 上传进度回调
const onUploadProgress = (item: any) => {
  filesMap.value.set(item.name, item)
  fileList.value = Array.from(filesMap.value.values())
}

// 上传结束回调
const onUploadEnd = (item: any) => {
  console.log('[onUploadEnd] 文件上传结束:', item.name, '状态:', item.type)
  filesMap.value.set(item.name, item)
  fileList.value = Array.from(filesMap.value.values())

  if (item.type === 'fail') {
    console.error(
      '[onUploadEnd] 文件上传失败:',
      item.name,
      '错误信息:',
      item.responseText || '未知错误',
    )
    uni.showToast({
      title: `${item.name}上传失败`,
      icon: 'none',
      duration: 2000,
    })
  }

  // 处理上传完成
  if (uploadStatus.value.isUploading) {
    uploadStatus.value.uploadedCount++
    console.log(
      '[onUploadEnd] 上传进度:',
      uploadStatus.value.uploadedCount,
      '/',
      uploadStatus.value.totalCount,
    )

    // 记录第一个文件的响应（用于最终返回）
    if (uploadStatus.value.uploadedCount === 1 && item.type === 'success' && item.responseText) {
      try {
        const response = JSON.parse(item.responseText)
        if (response.code === 200) {
          uploadStatus.value.firstResponse = response
          console.log('[onUploadEnd] 记录第一个文件的响应:', response)
        }
      } catch (e) {
        console.error('[onUploadEnd] 解析响应失败:', e, '原始响应:', item.responseText)
      }
    }

    // 所有文件上传完成（无论成功还是失败）
    if (uploadStatus.value.uploadedCount >= uploadStatus.value.totalCount) {
      console.log('[onUploadEnd] 所有文件上传完成，重置状态')
      uploadStatus.value.isUploading = false

      // 检查是否有失败的文件
      const failedFiles = fileList.value.filter((f: any) => f.type === 'fail')
      if (failedFiles.length > 0) {
        console.error(
          '[onUploadEnd] 有文件上传失败:',
          failedFiles.map((f: any) => f.name),
        )
        // 如果有失败的文件，返回错误
        uploadStatus.value.reject?.(
          new Error(`部分文件上传失败: ${failedFiles.map((f: any) => f.name).join(', ')}`),
        )
      } else {
        // 所有文件都成功，返回成功响应
        if (uploadStatus.value.firstResponse) {
          console.log('[onUploadEnd] 返回成功响应:', uploadStatus.value.firstResponse)
          uploadStatus.value.resolve?.(uploadStatus.value.firstResponse)
        } else {
          // 如果没有响应，创建一个成功响应
          console.log('[onUploadEnd] 创建成功响应')
          uploadStatus.value.resolve?.({
            code: 200,
            message: '上传成功',
            data: { id: uploadStatus.value.leaveId },
          })
        }
      }

      // 重置状态
      uploadStatus.value.uploadedCount = 0
      uploadStatus.value.totalCount = 0
      uploadStatus.value.firstResponse = null
      uploadStatus.value.leaveId = null
      uploadStatus.value.resolve = null
      uploadStatus.value.reject = null
    }
  } else {
    console.warn('[onUploadEnd] 收到上传结束回调，但 isUploading 为 false，可能是重复回调')
  }
}

// 格式化文件大小
const formatFileSize = (bytes: number): string => {
  if (!bytes || bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i]
}

// 获取文件状态文本
const getStatusText = (type: string): string => {
  const statusMap: Record<string, string> = {
    waiting: '待上传',
    loading: '上传中',
    success: '成功',
    fail: '失败',
  }
  return statusMap[type] || '未知'
}

// 删除文件
const removeFile = (fileName: string) => {
  ytUploadRef.value?.clear(fileName)
}

const handleAttachmentPreview = (attachment: LeaveApplicationAttachment) => {
  const url = attachment.fileUrl || attachment.filePath
  if (!url) {
    uni.showToast({ title: '暂无可预览文件', icon: 'none' })
    return
  }

  // 获取文件扩展名
  const fileName = attachment.fileName || ''
  const fileExtension = fileName.toLowerCase().split('.').pop() || ''

  // 判断是否为图片类型
  const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
  if (imageExtensions.includes(fileExtension)) {
    // 图片类型，使用 previewImage
    uni.previewImage({
      urls: [url],
      current: url,
    })
    return
  }

  // 其他文件类型（PDF、Word、Excel、PPT 等），使用 openDocument
  uni.showLoading({ title: '正在打开文档...' })

  uni.downloadFile({
    url,
    success: (res) => {
      if (res.statusCode === 200) {
        uni.openDocument({
          filePath: res.tempFilePath,
          fileType: fileExtension, // 指定文件类型：doc, docx, xls, xlsx, ppt, pptx, pdf
          showMenu: true, // 显示右上角菜单（分享、转发等）
          success: () => {
            uni.hideLoading()
            console.log('[handleAttachmentPreview] 文档打开成功')
          },
          fail: (err) => {
            uni.hideLoading()
            console.error('[handleAttachmentPreview] 文档打开失败:', err)

            // 提示用户可能的原因
            let errorMsg = '无法打开文档'
            if (err.errMsg && err.errMsg.includes('no application')) {
              errorMsg = '手机未安装支持的应用，请下载 WPS 或 Office'
            }

            uni.showModal({
              title: '提示',
              content: errorMsg + '\n是否直接下载文件？',
              confirmText: '下载',
              cancelText: '取消',
              success: (modalRes) => {
                if (modalRes.confirm) {
                  handleAttachmentDownload(attachment)
                }
              },
            })
          },
        })
      } else {
        uni.hideLoading()
        uni.showToast({
          title: '文件下载失败',
          icon: 'none',
        })
      }
    },
    fail: (err) => {
      uni.hideLoading()
      console.error('[handleAttachmentPreview] 下载失败:', err)
      uni.showToast({
        title: '文件下载失败，请检查网络',
        icon: 'none',
      })
    },
  })
}

// 下载附件到本地
const handleAttachmentDownload = (attachment: LeaveApplicationAttachment) => {
  const url = attachment.fileUrl || attachment.filePath
  if (!url) {
    uni.showToast({ title: '暂无可下载文件', icon: 'none' })
    return
  }

  uni.showLoading({ title: '下载中...' })

  uni.downloadFile({
    url,
    success: (res) => {
      if (res.statusCode === 200) {
        uni.saveFile({
          tempFilePath: res.tempFilePath,
          success: (saveRes) => {
            uni.hideLoading()
            console.log('[handleAttachmentDownload] 文件已保存到:', saveRes.savedFilePath)
            uni.showModal({
              title: '下载成功',
              content: '文件已保存到本地',
              showCancel: false,
              confirmText: '打开',
              success: (modalRes) => {
                if (modalRes.confirm) {
                  // 尝试打开文件
                  uni.openDocument({
                    filePath: saveRes.savedFilePath,
                    showMenu: true,
                    fail: (err) => {
                      console.error('[handleAttachmentDownload] 打开文件失败:', err)
                      uni.showToast({
                        title: '无法打开文件',
                        icon: 'none',
                      })
                    },
                  })
                }
              },
            })
          },
          fail: (saveErr) => {
            uni.hideLoading()
            console.error('[handleAttachmentDownload] 保存失败:', saveErr)
            uni.showToast({
              title: '文件保存失败',
              icon: 'none',
            })
          },
        })
      } else {
        uni.hideLoading()
        uni.showToast({
          title: `下载失败：状态码${res.statusCode}`,
          icon: 'none',
        })
      }
    },
    fail: (err) => {
      uni.hideLoading()
      console.error('[handleAttachmentDownload] 下载失败:', err)
      uni.showToast({
        title: `文件下载失败：${err.errMsg || '未知错误'}`,
        icon: 'none',
        duration: 3000,
      })
    },
  })
}

const handleAttachmentRemove = async (attachment: LeaveApplicationAttachment) => {
  if (!attachment.id) return
  try {
    await deleteLeaveAttachment(attachment.id)
    attachmentList.value = attachmentList.value.filter(
      (item: LeaveApplicationAttachment) => item.id !== attachment.id,
    )
    emit('attachment-removed', attachment.id)
    uni.showToast({ title: '附件已删除', icon: 'success' })
  } catch (error) {
    console.error('删除附件失败:', error)
    uni.showToast({ title: '删除附件失败', icon: 'none' })
  }
}

const validateForm = () => {
  if (!formData.applicantName) {
    uni.showToast({ title: '请输入姓名', icon: 'none' })
    return false
  }
  if (!formData.reason) {
    uni.showToast({ title: '请输入事由', icon: 'none' })
    return false
  }
  if (!formData.location) {
    uni.showToast({ title: `请输入${locationLabel.value}`, icon: 'none' })
    return false
  }
  if (!formData.startTime || !formData.endTime) {
    uni.showToast({ title: '请选择请假时间', icon: 'none' })
    return false
  }
  if (!formData.temporaryContactPerson) {
    uni.showToast({ title: '请输入临时负责人', icon: 'none' })
    return false
  }
  if (!formData.temporaryContactPhone) {
    uni.showToast({ title: '请输入负责人电话', icon: 'none' })
    return false
  }
  return true
}

/**
 * 上传文件（使用 yt-upload 组件）
 * 注意：此函数只负责上传文件，leaveId 必须已经存在
 */
const uploadFiles = async (leaveId: number): Promise<any> => {
  return new Promise((resolve, reject) => {
    if (!leaveId) {
      reject(new Error('请先保存请假申请，获取ID后再上传文件'))
      return
    }

    if (fileList.value.length === 0) {
      resolve({ code: 200, message: '没有文件需要上传', data: null })
      return
    }

    console.log(
      '[uploadFiles] 📤 准备上传文件，leaveId:',
      leaveId,
      '文件数量:',
      fileList.value.length,
    )

    // 检查文件状态，确保有等待上传的文件
    const waitingFiles = fileList.value.filter(
      (f: any) => f.type === 'waiting' || f.type === 'fail',
    )
    if (waitingFiles.length === 0) {
      console.warn(
        '[uploadFiles] 没有等待上传的文件，所有文件状态:',
        fileList.value.map((f: any) => ({ name: f.name, type: f.type })),
      )
      // 如果所有文件都是 success，直接返回成功
      const allSuccess = fileList.value.every((f: any) => f.type === 'success')
      if (allSuccess) {
        resolve({ code: 200, message: '所有文件已上传', data: { id: leaveId } })
        return
      }
      // 否则，重置文件状态为 waiting
      fileList.value.forEach((file: any) => {
        if (file.type !== 'success') {
          file.type = 'waiting'
          filesMap.value.set(file.name, file)
        }
      })
    }

    // 更新上传配置，使用新的附件上传接口
    updateUploadOption(leaveId)

    // #ifdef APP-PLUS
    // APP 平台：需要通过 setData 更新 WebView 内部的配置
    console.log('[uploadFiles] 更新 yt-upload 配置（APP平台）')
    ytUploadRef.value?.setData(uploadOption.value)

    // 多次设置确保生效（解决WebView更新延迟问题）
    setTimeout(() => {
      ytUploadRef.value?.setData(uploadOption.value)
      console.log('[uploadFiles] 第2次设置 option（50ms后）')
    }, 50)

    setTimeout(() => {
      ytUploadRef.value?.setData(uploadOption.value)
      console.log('[uploadFiles] 第3次设置 option（150ms后）')
    }, 150)
    // #endif

    // 设置上传状态
    uploadStatus.value.isUploading = true
    uploadStatus.value.uploadedCount = 0
    uploadStatus.value.totalCount = fileList.value.filter(
      (f: any) => f.type === 'waiting' || f.type === 'fail',
    ).length
    uploadStatus.value.firstResponse = null
    uploadStatus.value.leaveId = leaveId
    uploadStatus.value.resolve = resolve
    uploadStatus.value.reject = reject

    // 延迟调用 upload，确保配置更新生效
    setTimeout(() => {
      console.log('[uploadFiles] 调用 yt-upload.upload()，开始上传')
      console.log('[uploadFiles] 当前 option:', uploadOption.value)
      console.log('[uploadFiles] 等待上传的文件数量:', uploadStatus.value.totalCount)
      ytUploadRef.value?.upload()
    }, 300)

    // 超时保护
    setTimeout(() => {
      if (uploadStatus.value.isUploading) {
        console.error('[uploadFiles] 上传超时')
        console.error('[uploadFiles] 当前上传状态:', {
          isUploading: uploadStatus.value.isUploading,
          uploadedCount: uploadStatus.value.uploadedCount,
          totalCount: uploadStatus.value.totalCount,
          fileList: fileList.value.map((f: any) => ({ name: f.name, type: f.type })),
        })
        uploadStatus.value.isUploading = false
        reject(new Error('上传超时，请检查网络连接或文件大小'))
      }
    }, 120000)
  })
}

const saveForm = async () => {
  // 清理 undefined 和 null 值，避免 JSON.stringify 时出现问题
  const payload: any = {}
  Object.keys(formData).forEach((key) => {
    const value = (formData as any)[key]
    if (value !== undefined && value !== null) {
      payload[key] = value
    }
  })

  // 第一步：先保存请假申请（不传文件），获取ID
  const api = payload.id ? updateLeaveApplication : createLeaveApplication
  const saveResponse: any = await api(payload)
  const saveBody = saveResponse?.data || saveResponse
  if (saveBody?.code && saveBody.code !== 200) {
    throw new Error(saveBody.message || '保存失败')
  }
  const saveData = saveBody?.data || saveBody
  const leaveId = saveData?.id || payload.id
  if (!formData.id && leaveId) {
    formData.id = leaveId
    payload.id = leaveId
  }

  // 第二步：如果有文件，使用新的附件上传接口上传文件
  if (fileList.value.length > 0) {
    console.log(`[saveForm] 开始上传 ${fileList.value.length} 个文件，leaveId: ${leaveId}`)
    const uploadResponse: any = await uploadFiles(leaveId)
    const uploadBody = uploadResponse?.data || uploadResponse
    if (uploadBody?.code && uploadBody.code !== 200) {
      throw new Error(uploadBody.message || '文件上传失败')
    }
    console.log('[saveForm] 所有文件上传完成')
  }

  return leaveId as number
}

const handleSaveDraft = async () => {
  if (isViewMode.value) {
    uni.showToast({ title: '查看模式无法保存', icon: 'none' })
    return
  }
  if (!validateForm()) return
  try {
    submitting.value = true
    const id = await saveForm()
    emit('save-success', id)
    uni.showToast({ title: '保存成功', icon: 'success' })
  } catch (error: any) {
    uni.showToast({ title: error?.message || '保存失败', icon: 'none' })
  } finally {
    submitting.value = false
  }
}

const handleSubmit = async () => {
  if (isViewMode.value) {
    uni.showToast({ title: '查看模式无法提交', icon: 'none' })
    return
  }
  if (!validateForm()) return

  // 外部单位提交时需要验证报送单位联系人和联系电话
  if (props.formType !== 'internal') {
    if (!formData.reportingContactPerson) {
      uni.showToast({ title: '请输入报送单位联系人', icon: 'none' })
      return
    }
    if (!formData.reportingContactPhone) {
      uni.showToast({ title: '请输入联系电话', icon: 'none' })
      return
    }
  }

  try {
    submitting.value = true
    const id = await saveForm()
    if (id) {
      uni.showToast({ title: '保存成功！', icon: 'none' })
      emit('submit-success', id)
    }
  } catch (error: any) {
    uni.showToast({ title: error?.message || '提交失败', icon: 'none' })
  } finally {
    submitting.value = false
  }
}

const formatDateTime = (value?: string) => {
  if (!value) return '-'
  return value.replace('T', ' ').substring(0, 19)
}

/**
 * 判断流程记录是否已完成
 */
const isRecordCompleted = (record: LeaveApplicationApprovalRecord): boolean => {
  return (
    record.decision === 'reject' ||
    record.decision === 'agree' ||
    record.decision === 'approve' ||
    !!record.approveTime
  )
}

/**
 * 格式化流程记录时间
 * 只有已完成的记录才显示时间（审批完成时间）
 */
const formatRecordTime = (record: LeaveApplicationApprovalRecord) => {
  return formatDateTime(record.approveTime)
}

/**
 * 格式化流程记录日期为 YYYY/MM/DD 格式
 */
const formatRecordDate = (record: LeaveApplicationApprovalRecord) => {
  if (!record.approveTime) return '-'
  const dateStr = record.approveTime.substring(0, 10) // 提取日期部分 YYYY-MM-DD
  return dateStr.replace(/-/g, '/') // 将 - 替换为 /
}

const getRecordStatusType = (record: LeaveApplicationApprovalRecord) => {
  if (record.decision === 'reject') return 'error'
  if (record.decision === 'agree' || record.decision === 'approve') return 'success'
  // 如果有审批完成时间，也算作已完成
  if (record.approveTime) return 'success'
  return 'warning'
}

const getRecordStatusText = (record: LeaveApplicationApprovalRecord) => {
  if (record.decision === 'reject') return '已退回'
  if (record.decision === 'agree' || record.decision === 'approve') return '已完成'
  // 如果有审批完成时间，也算作已完成
  if (record.approveTime) return '已完成'
  return '进行中'
}

/**
 * 获取流程记录的状态样式类
 */
const getRecordStatusClass = (record: LeaveApplicationApprovalRecord) => {
  if (record.decision === 'reject') return 'status-rejected'
  if (record.decision === 'agree' || record.decision === 'approve') return 'status-completed'
  if (record.approveTime) return 'status-completed'
  return 'status-in-progress'
}

/**
 * 获取连接线的样式类（根据当前节点和下一个节点的状态）
 */
const getLineClass = (
  record: LeaveApplicationApprovalRecord,
  nextRecord?: LeaveApplicationApprovalRecord,
) => {
  // 如果当前节点被退回，连接线显示为红色
  if (record.decision === 'reject') return 'line-rejected'
  // 如果当前节点已完成，但下一个节点存在且未完成，连接线显示为渐变（绿色到黄色或红色）
  if (isRecordCompleted(record) && nextRecord) {
    if (nextRecord.decision === 'reject') return 'line-to-rejected'
    if (!isRecordCompleted(nextRecord)) return 'line-to-in-progress'
    return 'line-completed'
  }
  // 如果当前节点已完成，连接线显示为绿色
  if (isRecordCompleted(record)) return 'line-completed'
  // 如果当前节点进行中，连接线显示为黄色渐变
  return 'line-in-progress'
}

defineExpose({
  handleSaveDraft,
  handleSubmit,
})
</script>

<style scoped lang="scss">
.leave-form-base {
  display: flex;
  flex-direction: column;

  > * {
    margin-bottom: 32rpx;

    &:last-child {
      margin-bottom: 0;
    }
  }
}

.section-card {
  background: #ffffff;
  border-radius: 32rpx;
  padding: 18rpx 32rpx;
  border: 1rpx solid rgba(205, 214, 244, 0.8);
  position: relative;
  overflow: hidden;
}

.section-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 32rpx;
  border: 1rpx solid rgba(255, 255, 255, 0.6);
  pointer-events: none;
}

:deep(.u-tabs) {
  margin-bottom: 32rpx;
  padding: 0;
}

:deep(.u-tabs__wrapper__nav) {
  background: transparent;
}

:deep(.u-tabs__wrapper__nav__item) {
  font-size: 30rpx;
}

.tab-content {
  margin-top: 0;
}

.section-title {
  font-size: 34rpx;
  font-weight: 700;
  color: #1f2b5b;
  margin-bottom: 28rpx;
  display: flex;
  align-items: center;

  &::before {
    content: '';
    width: 12rpx;
    height: 36rpx;
    border-radius: 6rpx;
    background: linear-gradient(180deg, #5f87ff 0%, #52e5ff 100%);
    box-shadow: 0 6rpx 18rpx rgba(82, 229, 255, 0.4);
    margin-right: 14rpx;
  }
}

.form-grid {
  display: flex;
  flex-direction: column;

  > * {
    margin-bottom: 26rpx;
  }
}

.form-item {
  display: flex;
  align-items: center;

  .label {
    font-size: 28rpx;
    color: #5a6380;
    font-weight: 600;
    min-width: 150rpx;
    margin-right: 24rpx;
  }

  &.vertical {
    flex-direction: column;
    align-items: flex-start;

    .label {
      min-width: auto;
      margin-right: 0;
      margin-bottom: 14rpx;
    }

    > *:not(.label) {
      margin-bottom: 14rpx;

      &:last-child {
        margin-bottom: 0;
      }
    }
  }
}

.form-item:not(.vertical) > u-input,
.form-item:not(.vertical) > .picker-wrapper,
.form-item:not(.vertical) > u-textarea,
.form-item:not(.vertical) > view:not(.label) {
  flex: 1;
  width: 100%;
}

.picker-wrapper {
  background: transparent;
  border: none;
  border-bottom: 2rpx solid #dce2ff;
  height: 68rpx;
  display: flex;
  align-items: center;
  padding: 0;
  box-shadow: none;
  width: 100%;
}

.picker-wrapper :deep(.uni-date-editor) {
  width: 100%;
  padding: 0 !important;
  background: #ffffff !important;
  border: none !important;
  box-shadow: none !important;
}

.picker-wrapper :deep(.uni-date-editor__input) {
  border: none !important;
  border-bottom: 2rpx solid #dce2ff !important;
  border-radius: 0 !important;
  padding: 0 !important;
  height: 68rpx;
  font-size: 30rpx;
  background: transparent !important;
}

.attachment-section {
  display: flex;
  flex-direction: column;

  > * {
    margin-bottom: 16rpx;

    &:last-child {
      margin-bottom: 0;
    }
  }
}

.remark-inline {
  margin-top: 32rpx;
}

.timeline-card {
  background: linear-gradient(180deg, #ffffff 0%, #f2f6ff 100%);
  border: 1rpx solid rgba(184, 198, 255, 0.6);
}

.attachment-list {
  display: flex;
  flex-direction: column;

  > * {
    margin-bottom: 12rpx;

    &:last-child {
      margin-bottom: 0;
    }
  }
}

.attachment-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16rpx 20rpx;
  border: 1rpx solid #edf0f5;
  border-radius: 16rpx;

  .info {
    display: flex;
    align-items: center;

    .name {
      font-size: 26rpx;
      color: #303133;
      margin-left: 12rpx;
    }
  }
}

.empty-attachment {
  font-size: 26rpx;
  color: #c0c4cc;
}

.upload-box {
  margin-top: 20rpx;

  .upload-btn-slot {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20rpx;
    background: linear-gradient(135deg, #f0f4ff 0%, #e8f0ff 100%);
    border: 2rpx dashed #5f87ff;
    border-radius: 16rpx;
    cursor: pointer;
    transition: all 0.3s;

    .upload-icon {
      font-size: 40rpx;
    }

    .upload-text {
      font-size: 28rpx;
      color: #5f87ff;
      font-weight: 500;
      margin-left: 12rpx;
    }
  }

  .upload-tip {
    display: block;
    margin-top: 12rpx;
    font-size: 24rpx;
    color: #a0a4ab;
  }

  .file-list {
    margin-top: 20rpx;
    display: flex;
    flex-direction: column;

    .file-item {
      margin-bottom: 12rpx;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16rpx 20rpx;
      background: linear-gradient(180deg, #ffffff 0%, #f8faff 100%);
      border: 1rpx solid rgba(95, 135, 255, 0.2);
      border-radius: 12rpx;
      box-shadow: 0 2rpx 8rpx rgba(95, 135, 255, 0.1);

      &:last-child {
        margin-bottom: 0;
      }

      .file-info {
        flex: 1;
        display: flex;
        flex-direction: column;
        min-width: 0;

        .file-name {
          font-size: 28rpx;
          color: #1f2b5b;
          font-weight: 500;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        .file-size {
          font-size: 24rpx;
          color: #8b90a5;
          margin-top: 8rpx;
        }

        .file-status {
          margin-top: 8rpx;
          font-size: 24rpx;
          padding: 4rpx 12rpx;
          border-radius: 8rpx;
          display: inline-block;
          width: fit-content;

          &.status-waiting {
            color: #8b90a5;
            background: #f0f2f5;
          }

          &.status-loading {
            color: #5f87ff;
            background: #e8f0ff;
          }

          &.status-success {
            color: #52c41a;
            background: #f0f9ff;
          }

          &.status-fail {
            color: #f56c6c;
            background: #fff0f0;
          }
        }
      }

      .file-delete {
        width: 48rpx;
        height: 48rpx;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 40rpx;
        color: #f56c6c;
        cursor: pointer;
        border-radius: 50%;
        transition: all 0.3s;

        &:active {
          background: rgba(245, 108, 108, 0.1);
        }
      }
    }
  }
}

.flow-timeline {
  position: relative;
}

.flow-item {
  position: relative;
  margin-bottom: 32rpx;

  &:last-child {
    margin-bottom: 0;
  }
}

.flow-content {
  display: flex;
  align-items: flex-start;
  position: relative;
}

.flow-timeline-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-right: 24rpx;
  position: relative;
}

.flow-status-dot {
  width: 32rpx;
  height: 32rpx;
  border-radius: 50%;
  flex-shrink: 0;
  position: relative;
  z-index: 2;
  border: 4rpx solid #fff;
  box-sizing: border-box;

  &.status-completed {
    background: #52c41a;
    box-shadow: 0 0 0 2rpx rgba(82, 196, 26, 0.2);
  }

  &.status-in-progress {
    background: #ffc107;
    box-shadow: 0 0 0 2rpx rgba(255, 193, 7, 0.2);
  }

  &.status-rejected {
    background: #f56c6c;
    box-shadow: 0 0 0 2rpx rgba(245, 108, 108, 0.2);
  }
}

.flow-line {
  width: 4rpx;
  height: 170rpx;
  margin-top: 8rpx;
  position: relative;

  &.line-completed {
    background: #52c41a;
  }

  &.line-in-progress {
    background: linear-gradient(to bottom, #52c41a 0%, #ffc107 100%);
  }

  &.line-rejected {
    background: #f56c6c;
  }

  &.line-to-in-progress {
    background: linear-gradient(to bottom, #52c41a 0%, #ffc107 100%);
  }

  &.line-to-rejected {
    background: linear-gradient(to bottom, #52c41a 0%, #f56c6c 100%);
  }
}

.flow-right {
  flex: 1;
  display: flex;
  flex-direction: column;

  > * {
    margin-bottom: 12rpx;

    &:last-child {
      margin-bottom: 0;
    }
  }
}

.flow-header {
  display: flex;
  justify-content: space-between;
  align-items: center;

  .step-name {
    font-size: 30rpx;
    font-weight: 600;
    color: #303133;
  }
}

.flow-body {
  display: flex;
  align-items: center;
  font-size: 26rpx;
  color: #606266;

  .approver-label {
    color: #909399;
    margin-right: 8rpx;
  }

  .approver-name {
    color: #303133;
    font-weight: 500;
  }
}

.flow-opinion-box {
  background: #f5f5f5;
  border-radius: 8rpx;
  padding: 16rpx 20rpx;
  font-size: 26rpx;
  line-height: 1.6;

  .opinion-label {
    color: #909399;
    margin-right: 8rpx;
  }

  .opinion-text {
    color: #606266;
  }
}

.flow-time {
  font-size: 24rpx;
  color: #909399;

  .waiting-text {
    color: #909399;
    font-style: italic;
  }
}
</style>
